use actix_web::{HttpResponse, Responder, http::header::ContentType};
use serde::{Deserialize, Serialize, Serializer};
use std::{
    hash::{Hash, Hasher},
    net::IpAddr,
    ops::Deref,
    sync::{Arc, Mutex},
};
use uuid::Uuid;

use crate::{RegistryError, db::State};

pub struct ServiceStorage {
    state: Arc<Mutex<State>>,
}

impl Default for ServiceStorage {
    fn default() -> Self {
        ServiceStorage {
            state: Arc::new(Mutex::new(State::new())),
        }
    }
}

impl Deref for ServiceStorage {
    type Target = Arc<Mutex<State>>;

    fn deref(&self) -> &Self::Target {
        &self.state
    }
}

#[derive(Debug, Deserialize, Clone)]
pub struct Service {
    pub name: String,
    pub group: String,
    pub tag: Option<Vec<String>>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Entity {
    pub uid: Uuid,
    pub host: IpAddr,
    pub port: u16,
    pub name: String,
    pub group: String,
    pub tag: Option<Vec<String>>,
}

impl Entity {
    pub fn from(service: Service, host: IpAddr, port: u16) -> Self {
        Entity {
            uid: Uuid::new_v4(),
            host,
            port,
            name: service.name,
            group: service.group,
            tag: service.tag,
        }
    }
}

#[derive(Debug, Deserialize)]
pub enum FilterBy {
    #[serde(rename = "group")]
    Group,
    #[serde(rename = "name")]
    Name,
    #[serde(rename = "uid")]
    Uuid,
}

#[derive(Debug, Deserialize)]
pub struct Query {
    pub filter_by: FilterBy,
    pub key: String,
}

#[derive(Debug, Serialize)]
pub struct Response<T: Serialize> {
    code: u16,
    message: Option<RegistryError>,
    data: Option<T>,
}

// Vec<SerializableEntity>

impl<T: Serialize> Response<T> {
    pub fn success() -> Self {
        Response {
            code: 0,
            message: None,
            data: None,
        }
    }

    pub fn ok(data: T) -> Self {
        Response {
            code: 0,
            message: None,
            data: Some(data),
        }
    }

    pub fn failure(code: u16, message: Option<RegistryError>) -> Self {
        Response {
            code,
            message,
            data: None,
        }
    }

    pub fn with(code: u16, message: Option<RegistryError>, data: Option<T>) -> Self {
        Response {
            code,
            message,
            data,
        }
    }
}

#[derive(Deserialize)]
pub struct Unregister{
    pub uid: Uuid
}


// Vec<SerializableEntity>

impl<T: Serialize> Responder for Response<T> {
    type Body = actix_web::body::BoxBody;

    fn respond_to(self, _req: &actix_web::HttpRequest) -> actix_web::HttpResponse<Self::Body> {
        let body = serde_json::to_string(&self).unwrap();

        HttpResponse::Ok()
            .content_type(ContentType::json())
            .body(body)
    }
}

#[derive(Debug)]
pub struct EntityRef(pub Arc<Entity>);

impl EntityRef {
    pub fn clone(arc_entity: &Arc<Entity>) -> Self {
        EntityRef(Arc::clone(&arc_entity))
    }
}

impl PartialEq for EntityRef {
    fn eq(&self, other: &Self) -> bool {
        self.0.uid == other.0.uid
    }
}

impl Deref for EntityRef {
    type Target = Arc<Entity>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl Hash for EntityRef {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.uid.hash(state);
    }
}

impl Eq for EntityRef {}

impl Serialize for EntityRef {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        Serialize::serialize(&*self.0, serializer)
    }
}
